package com.feather.common.converter.simple;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;

import com.feather.common.converter.FieldAssignment;
import com.feather.common.converter.FieldAssignmentHelper;
import com.feather.common.converter.simple.fieldassignment.*;

/**
 * @author flogyin
 */
public class SimpleFieldAssignmentHelper implements FieldAssignmentHelper {
	private String								_null			= "";
	private String								link			= "|";

	private HashMap<String, FieldAssignment>	assignmentMap	= new HashMap<String, FieldAssignment>();

	public SimpleFieldAssignmentHelper() {
		// java.lang.String ->
		String_Boolean String_Boolean = new String_Boolean();
		register(String.class, boolean.class, String_Boolean);// String ->
																// boolean
		register(String.class, Boolean.class, String_Boolean);// String ->
																// java.lang.Boolean
		register(null, boolean.class, String_Boolean);// null -> boolean
		register(null, Boolean.class, String_Boolean);// null ->
														// java.lang.Boolean

		String_Byte String_Byte = new String_Byte();
		register(String.class, byte.class, String_Byte);// String -> byte
		register(String.class, Byte.class, String_Byte);// String ->
														// java.lang.Byte
		register(null, byte.class, String_Byte);// null -> byte
		register(null, Byte.class, String_Byte);// null -> java.lang.Byte

		String_Character String_Character = new String_Character();
		register(String.class, char.class, String_Character);// String -> char
		register(String.class, Character.class, String_Character);// String ->
																	// java.lang.Character
		register(null, char.class, String_Character);// null -> char
		register(null, Character.class, String_Character);// null ->
															// java.lang.Character

		String_Double String_Double = new String_Double();
		register(String.class, double.class, String_Double);// String -> double
		register(String.class, Double.class, String_Double);// String ->
															// java.lang.Double
		register(null, double.class, String_Double);// null -> double
		register(null, Double.class, String_Double);// null -> java.lang.Double

		String_Float String_Float = new String_Float();
		register(String.class, float.class, String_Float);// String -> float
		register(String.class, Float.class, String_Float);// String ->
															// java.lang.Float
		register(null, float.class, String_Float);// null -> float
		register(null, Float.class, String_Float);// null -> java.lang.Float

		String_Integer String_Integer = new String_Integer();
		register(String.class, int.class, String_Integer);// String -> int
		register(String.class, Integer.class, String_Integer);// String ->
																// java.lang.Integer
		register(null, int.class, String_Integer);// null -> int
		register(null, Integer.class, String_Integer);// null ->
														// java.lang.Integer

		String_Long String_Long = new String_Long();
		register(String.class, long.class, String_Long);// String -> long
		register(String.class, Long.class, String_Long);// String ->
														// java.lang.Long
		register(null, long.class, String_Long);// null -> long
		register(null, Long.class, String_Long);// null -> java.lang.Long

		String_Short String_Short = new String_Short();
		register(String.class, short.class, String_Short);// String -> short
		register(String.class, Short.class, String_Short);// String ->
															// java.lang.Short
		register(null, short.class, String_Short);// null -> short
		register(null, Short.class, String_Short);// null -> java.lang.Short

		Object_Object Object_Object = new Object_Object();
		register(String.class, String.class, Object_Object);// String -> String
		register(String.class, String[].class, new String_StringArray());// String
																			// ->
																			// String[]
		register(String.class, StringBuffer.class, new String_StringBuffer());// String
																				// ->
																				// java.lang.StringBuffer
		register(String.class, StringBuilder.class, new String_StringBuilder());// String
																				// ->
																				// java.lang.StringBuilder
		register(null, String.class, Object_Object);// null -> String
		register(null, String[].class, new String_StringArray());// null ->
																	// String[]
		register(null, StringBuilder.class, new String_StringBuilder());// null
																		// ->
																		// java.lang.StringBuilder

		// java.lang.String[] ->
		register(String[].class, boolean.class, new StringArray_Boolean());// String[]
																			// ->
																			// boolean
		register(String[].class, Boolean.class, new StringArray_Boolean());// String[]
																			// ->
																			// java.lang.Boolean
		register(null, boolean.class, new StringArray_Boolean());// null ->
																	// boolean
		register(null, Boolean.class, new StringArray_Boolean());// null ->
																	// java.lang.Boolean

		register(String[].class, byte.class, new StringArray_Byte());// String[]
																		// ->
																		// byte
		register(String[].class, Byte.class, new StringArray_Byte());// String[]
																		// ->
																		// java.lang.Byte
		register(null, byte.class, new StringArray_Byte());// null -> byte
		register(null, Byte.class, new StringArray_Byte());// null ->
															// java.lang.Byte

		register(String[].class, char.class, new StringArray_Character());// String[]
																			// ->
																			// char
		register(String[].class, Character.class, new StringArray_Character());// String[]
																				// ->
																				// java.lang.Character
		register(null, char.class, new StringArray_Character());// null -> char
		register(null, Character.class, new StringArray_Character());// null ->
																		// java.lang.Character

		register(String[].class, double.class, new StringArray_Double());// String[]
																			// ->
																			// double
		register(String[].class, Double.class, new StringArray_Double());// String[]
																			// ->
																			// java.lang.Double
		register(null, double.class, new StringArray_Double());// null -> double
		register(null, Double.class, new StringArray_Double());// null ->
																// java.lang.Double

		register(String[].class, float.class, new StringArray_Float());// String[]
																		// ->
																		// float
		register(String[].class, Float.class, new StringArray_Float());// String[]
																		// ->
																		// java.lang.Float
		register(null, float.class, new StringArray_Float());// null -> float
		register(null, Float.class, new StringArray_Float());// null ->
																// java.lang.Float

		register(String[].class, int.class, new StringArray_Integer());// String[]
																		// ->
																		// int
		register(String[].class, Integer.class, new StringArray_Integer());// String[]
																			// ->
																			// java.lang.Integer
		register(null, int.class, new StringArray_Integer());// null -> int
		register(null, Integer.class, new StringArray_Integer());// null ->
																	// java.lang.Integer

		register(String[].class, long.class, new StringArray_Long());// String[]
																		// ->
																		// long
		register(String[].class, Long.class, new StringArray_Long());// String[]
																		// ->
																		// java.lang.Long
		register(null, long.class, new StringArray_Long());// null -> long
		register(null, Long.class, new StringArray_Long());// null ->
															// java.lang.Long

		register(String[].class, short.class, new StringArray_Short());// String[]
																		// ->
																		// short
		register(String[].class, Short.class, new StringArray_Short());// String[]
																		// ->
																		// java.lang.Short
		register(null, short.class, new StringArray_Short());// null -> short
		register(null, Short.class, new StringArray_Short());// null ->
																// java.lang.Short

		register(String[].class, String.class, new StringArray_String());// String[]
																			// ->
																			// String
		register(String[].class, String[].class, Object_Object);// String[] ->
																// String[]
		register(null, String.class, new StringArray_String());// null -> String
		register(null, String[].class, Object_Object);// null -> String[]
	}

	@SuppressWarnings("rawtypes")
	public void register(Class value, Class to, FieldAssignment convertible) {
		String key = key(value, to);
		this.assignmentMap.put(key, convertible);
	}

	@SuppressWarnings("rawtypes")
	public void remove(Class value, Class to) {
		String key = key(value, to);
		this.assignmentMap.remove(key);
	}

	@Override
	public void clear() {
		this.assignmentMap.clear();
	}

	@Override
	@SuppressWarnings("rawtypes")
	public FieldAssignment lookup(Class value, Class to) {
		String key = key(value, to);
		return this.assignmentMap.get(key);
	}

	@Override
	@SuppressWarnings("rawtypes")
	public Object assign(Object value, Object obj, Field field) {
		if (!Modifier.isFinal(field.getModifiers())) {
			Class valueType = null;
			if (value != null) {
				valueType = value.getClass();
			}
			Class fieldType = field.getType();
			FieldAssignment assignment = this.lookup(valueType, fieldType);
			// System.out.println("FieldAssignment: "+ key +"\t["+ value +"]");

			if (assignment != null) {
				Object chainV = assignment.assign(value, obj, field);
				if (chainV != null)
					return assign(chainV, obj, field);
			} else {
				throw new RuntimeException("Not found FieldAssignment: " + field.getName() + ".");
			}
		}
		return null;
	}

	@SuppressWarnings("rawtypes")
	protected String key(Class value, Class to) {
		String valueName = null;
		if (value != null) {
			valueName = value.getName();
		} else {
			valueName = this._null;
		}
		return valueName + this.link + to.getName();
	}
}
